#include "Bsp_Sound.h"

#include "driver/i2c_master.h"
#include "driver/i2s_std.h"
#include "driver/i2s_tdm.h"
#include "esp_check.h"
#include "soc/soc_caps.h"

#include "esp_codec_dev.h"
#include "esp_codec_dev_defaults.h"

#define I2C_SDA_PIN GPIO_NUM_0
#define I2C_SCL_PIN GPIO_NUM_1

#define I2S_BCK_PIN GPIO_NUM_2
#define I2S_MCLK_PIN GPIO_NUM_3

#define I2S_DATA_IN_PIN GPIO_NUM_4
#define I2S_DATA_OUT_PIN GPIO_NUM_6
#define I2S_WS_PIN GPIO_NUM_5

#define PA_PIN GPIO_NUM_7 // 功放使能引脚，如果没有可设为 -1

static i2c_master_bus_handle_t i2c_bus_handle = NULL;
static i2s_chan_handle_t tx_handle = NULL;
static i2s_chan_handle_t rx_handle = NULL;

static const char *TAG = "smart_doorbell";
static esp_codec_dev_handle_t codec_dev = NULL;

static esp_err_t ut_i2c_init()
{

  i2c_master_bus_config_t i2c_bus_config = {0};
  i2c_bus_config.clk_source = I2C_CLK_SRC_DEFAULT;
  i2c_bus_config.i2c_port = I2C_NUM_0;
  i2c_bus_config.scl_io_num = I2C_SCL_PIN;
  i2c_bus_config.sda_io_num = I2C_SDA_PIN;
  i2c_bus_config.glitch_ignore_cnt = 7;
  i2c_bus_config.flags.enable_internal_pullup = true;
  return i2c_new_master_bus(&i2c_bus_config, &i2c_bus_handle);
}

static esp_err_t ut_i2s_init()
{

  // I2S 通道配置
  i2s_chan_config_t chan_cfg =
      I2S_CHANNEL_DEFAULT_CONFIG(I2S_NUM_0, I2S_ROLE_MASTER);
  ESP_RETURN_ON_ERROR(i2s_new_channel(&chan_cfg, &tx_handle, &rx_handle), TAG,
                      "I2S channel creation failed");

  // I2S 标准配置
  i2s_std_config_t std_cfg = {
      .clk_cfg = I2S_STD_CLK_DEFAULT_CONFIG(16000), // 16kHz 采样率
      .slot_cfg = I2S_STD_PHILIPS_SLOT_DEFAULT_CONFIG(
          16, I2S_SLOT_MODE_MONO), // 16位的采样深度 单声道
      .gpio_cfg =
          {
              .mclk = I2S_MCLK_PIN,
              .bclk = I2S_BCK_PIN,
              .ws = I2S_WS_PIN,
              .dout = I2S_DATA_OUT_PIN,
              .din = I2S_DATA_IN_PIN,
          },
  };

  // 初始化 TX 和 RX 通道
  ESP_RETURN_ON_ERROR(i2s_channel_init_std_mode(tx_handle, &std_cfg), TAG,
                      "TX init failed");
  ESP_RETURN_ON_ERROR(i2s_channel_init_std_mode(rx_handle, &std_cfg), TAG,
                      "RX init failed");

  // 启用通道
  ESP_RETURN_ON_ERROR(i2s_channel_enable(tx_handle), TAG, "TX enable failed");
  ESP_RETURN_ON_ERROR(i2s_channel_enable(rx_handle), TAG, "RX enable failed");
  return ESP_OK;
}

void bsp_sound_es8311_init(void)
{

  audio_codec_i2s_cfg_t i2s_cfg = {
      .rx_handle = rx_handle,
      .tx_handle = tx_handle,
  };
  const audio_codec_data_if_t *data_if = audio_codec_new_i2s_data(&i2s_cfg);

  audio_codec_i2c_cfg_t i2c_cfg = {.addr = ES8311_CODEC_DEFAULT_ADDR,
                                   .bus_handle = i2c_bus_handle,
                                   .port = I2C_NUM_0};
  const audio_codec_ctrl_if_t *out_ctrl_if = audio_codec_new_i2c_ctrl(&i2c_cfg);

  const audio_codec_gpio_if_t *gpio_if = audio_codec_new_gpio();

  es8311_codec_cfg_t es8311_cfg = {
      .codec_mode = ESP_CODEC_DEV_WORK_MODE_BOTH,
      .ctrl_if = out_ctrl_if,
      .gpio_if = gpio_if,
      .pa_pin = PA_PIN,
      .use_mclk = true,
  };
  const audio_codec_if_t *out_codec_if = es8311_codec_new(&es8311_cfg);

  esp_codec_dev_cfg_t dev_cfg = {
      .codec_if = out_codec_if,              // es8311_codec_new 获取到的接口实现
      .data_if = data_if,                    // audio_codec_new_i2s_data 获取到的数据接口实现
      .dev_type = ESP_CODEC_DEV_TYPE_IN_OUT, // 设备同时支持录制和播放
  };
  codec_dev = esp_codec_dev_new(&dev_cfg);
  // 以下代码展示如何播放音频

  esp_codec_dev_set_out_vol(codec_dev, 60.0);
  esp_codec_dev_set_in_gain(codec_dev, 20.0);
  // uint8_t data[256];
  // esp_codec_dev_write(codec_dev, data, sizeof(data));

  // esp_codec_dev_read(codec_dev, data, sizeof(data));
  // esp_codec_dev_close(codec_dev);
}

void bsp_sound_init(void)
{
  // 初始化I2C

  ut_i2c_init();
  // 初始化I2S
  ut_i2s_init();

  // 初始化es8311
  bsp_sound_es8311_init();
}

int bsp_sound_write(uint8_t *data, int size)
{
  if (codec_dev && data && size > 0)
  {

    return esp_codec_dev_write(codec_dev, (void *)data, size);
  }

  return ESP_CODEC_DEV_WRITE_FAIL;
}

int bsp_sound_read(uint8_t data[], int size)
{
  if (codec_dev && data && size > 0)
  {
    return esp_codec_dev_read(codec_dev, data, size);
  }

  return ESP_CODEC_DEV_READ_FAIL;
}

void bsp_sound_open(void)
{

  esp_codec_dev_sample_info_t fs = {
      .sample_rate = 16000,
      .channel = 1,
      .bits_per_sample = 16,
  };
  if (codec_dev != NULL)
  {
    esp_codec_dev_open(codec_dev, &fs);
  }
}

void bsp_sound_close(void)
{
  if (codec_dev != NULL)
  {
    esp_codec_dev_close(codec_dev);
  }
}

static int s_volume = 60;
void bsp_sound_set_volume(int volume)
{
  if (codec_dev != NULL)
  {
    s_volume = volume;
    esp_codec_dev_set_out_vol(codec_dev, volume);
  }
}

void bsp_sound_set_mute(bool mute)
{
  if (codec_dev != NULL)
  {
    if (mute)
    {
      esp_codec_dev_set_out_vol(codec_dev, 0);
    }
    else
    {
      esp_codec_dev_set_out_vol(codec_dev, s_volume);
    }
  }
}